/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>

#if defined(_WIN32)
#include <winsock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <windows.h>
#endif

#include "zlang_in.h"

#if ( defined _WIN32 )
#include "openssl/applink.c"
#endif

#if defined(_WIN32)
#pragma comment(linker,"/stack:"WINZLANG_MAX_STACK_SIZE)
#elif defined(__linux__)
#endif

/*
 * VS2019 DEBUG PARAMETERS BACKUP :
 *     test_list_BatchRegexpMatchReserved_2.z
 *     $(SolutionDir)..\test\
 *     ZEUX.z
 *     D:\Work\Zlang Projects\ZEUX\src
 */

#if defined(_WIN32)
TLS static struct ZlangRuntime		*_alart_rt = NULL ;
TLS static struct StackFrameInfo	*_alart_stack_frames_info = NULL  ;
TLS static size_t			_alart_stack_frames_count = 0 ;
TLS static size_t			_alart_stack_frames_no = 0 ;
TLS static signed long			_alart_stack_depth = 0 ;

LONG ApplicationCrashHandler( EXCEPTION_POINTERS *pException )
{
	_alart_rt = GetZlangRuntime() ;

	printf( "zlang crashed\n" );

	printf( "--- crash info ---------\n" );
	printf( "Address :0x%p\n" , pException->ExceptionRecord->ExceptionAddress );
	printf( "ErrorCode :0x%X\n" , pException->ExceptionRecord->ExceptionCode );
	printf( "Flags :0x%X\n" , pException->ExceptionRecord->ExceptionFlags );

	_alart_stack_frames_info = GetStackFramesInfo( pException->ContextRecord , & _alart_stack_frames_count ) ;
	if( _alart_stack_frames_info == NULL )
	{
		printf( "GetStackFramesInfo failed\n" );
		return EXCEPTION_EXECUTE_HANDLER;
	}
	
	printf( "--- zlang stack frames ---------\n" );
	for( _alart_stack_frames_no = 0 ; _alart_stack_frames_no < _alart_stack_frames_count ; _alart_stack_frames_no++ )
	{
		printf( "frame %zu : %s (%s:%zu) ST[%"PRIu64"] SD[%ld]\n" , _alart_stack_frames_no , _alart_stack_frames_info[_alart_stack_frames_no].func_name , _alart_stack_frames_info[_alart_stack_frames_no].source_filename , _alart_stack_frames_info[_alart_stack_frames_no].source_fileline , (uint64_t)(_alart_rt->zlang_stack_bottom)-_alart_stack_frames_info[_alart_stack_frames_no].stack_top , _alart_stack_frames_info[_alart_stack_frames_no].stack_depth );
	}
	
	return EXCEPTION_EXECUTE_HANDLER;
}
#elif defined(__linux__)
void SignalHandler( int signal_no )
{
	printf( "zlang unexpection signal\n" );
	
	printf( "--- signal info ---------\n" );
	printf( "signal no[%d]\n" , signal_no );
	
	INIT_STACK_FRAMES_CONTEXT
	_alart_stack_frames_info = GetStackFramesInfo( NULL , & _alart_stack_frames_count ) ;
	if( _alart_stack_frames_info == NULL )
	{
		printf( "GetStackFramesInfo failed\n" );
		exit(4);
	}
	
	printf( "--- zlang stack frames ---------\n" );
	for( _alart_stack_frames_no = 0 ; _alart_stack_frames_no < _alart_stack_frames_count ; _alart_stack_frames_no++ )
	{
		printf( "frame %zu : %s (%s:%zu)\n" , _alart_stack_frames_no , _alart_stack_frames_info[_alart_stack_frames_no].func_name , _alart_stack_frames_info[_alart_stack_frames_no].source_filename , _alart_stack_frames_info[_alart_stack_frames_no].source_fileline );
	}
	
	exit(4);
}
#endif

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdLine, int nShow)
{
	int		argc ;
	char		**argv = NULL ;
	int		nret = 0 ;

#if defined(_WIN32)
	SetUnhandledExceptionFilter( ApplicationCrashHandler );
#elif defined(__linux__)
	signal( SIGSEGV , SignalHandler );
	signal( SIGILL , SignalHandler );
	signal( SIGFPE , SignalHandler );
	signal( SIGBUS , SignalHandler );
#endif

#if defined(_WIN32)
	WSADATA		wsaData;

	nret = WSAStartup( MAKEWORD(2, 2) , & wsaData ) ;
	if( nret != NO_ERROR )
	{
		printf( "WSAStartup failed[%d]\n" , nret );
		return 1;
	}
#endif

	argv = CommandLineToArgvA( GetCommandLine() , & argc ) ;
	if( argv == NULL )
	{
		printf( "CommandLineToArgv failed\n" );
		return 1;
	}

	nret = zlang( argc , argv ) ;

	FreeArgvA( argv , argc );

#if defined(_WIN32)
	WSACleanup();
#endif

	return nret;
}
